#ifndef VZCONN_CONN_VZCONNECT_H_
#define VZCONN_CONN_VZCONNECT_H_

#include "vzconn/base/basicdefines.h"
#include "vzconn/base/bytebuffer.h"

namespace vzconn {

static const char* VZ_HEADER = "VZ";

class VzConnect : public boost::noncopyable,
  public boost::enable_shared_from_this<VzConnect> {
 public:
  enum ConnState {
    CS_CLOSED,
    CS_CONNECTED
  };
  typedef boost::shared_ptr<VzConnect> Ptr;

  boost::signals2::signal<void(
    VzConnect::Ptr connect,
    const boost::system::error_code& err)> SignalConnectError;

  boost::signals2::signal<void(
    VzConnect::Ptr connect)> SignalConnectWrite;

  boost::signals2::signal<void(
    VzConnect::Ptr connect,
    const char* buffer,
    int size, int flag)> SignalConnectRead;

  virtual ~VzConnect();

  virtual bool Start() = 0;

  virtual const std::string ip_addr() = 0;

  virtual bool IsConnected() const = 0;

  // THREAD SAFE
  // Close the connect
  virtual void CloseConnect();

  virtual boost::asio::io_service& io_service() {
    return io_service_;
  }

  virtual ConnState GetState() const {
    return state_;
  }

  // The size must small than 16 MB
  bool AsyncWrite(const char* data, int size, int flag = 0);

  bool AsyncWrite(ByteBuffer::Ptr buffer, int flag = 0);

 public:
  //
  virtual void AsyncReadData() = 0;
  virtual void ConnectError(const boost::system::error_code& err) = 0;
  virtual void TryToWriteData() = 0;
  virtual void HandleCloseConnect() = 0;

  void HandleReadData(const boost::system::error_code& err,
                      int read_size);
  void HandleAsyncWrite(ByteBuffer::Ptr buffer, uint16 flag);
  void HandleDataWrite(const boost::system::error_code& err,
                       ByteBuffer::Ptr write_buffer,
                       int write_size);
 protected:
  VzConnect(boost::asio::io_service &io_service);
 protected:
  static const int HEADER_BUFFERR_SIZE = 8;
  static const int PRE_BUFFER_SIZE = 1024 * 4;
  static const int MAX_PKT_SIZE = 1024 * 1024 * 16;
  boost::asio::io_service &io_service_;

  bool is_writing_;
  boost::scoped_ptr<ByteBuffer> read_buffer_;
  char pre_read_buffer_[PRE_BUFFER_SIZE];
  char read_header_buffer_[HEADER_BUFFERR_SIZE];
  std::vector<ByteBuffer::Ptr> buffers_;

  ConnState state_;
};

////////////////////////////////////////////////////////////////////////////////

class BlockVzConnect : public boost::noncopyable,
  public boost::enable_shared_from_this<BlockVzConnect> {
 public:
  typedef boost::shared_ptr<BlockVzConnect> Ptr;
  virtual ~BlockVzConnect();
  bool SyncWrite(const char *data, uint32 size, uint16 flag = 0);
  bool SyncRead(std::vector<char> &read_buffer, uint16 *flag = NULL);
  virtual void CloseConnect() = 0;
  virtual bool IsConnected() = 0;
 protected:
  virtual bool RealySyncWrite(
    std::vector<boost::asio::const_buffer> &buffers) = 0;
  virtual bool RealySyncRead(char *buffer, uint32 buffer_size) = 0;
 protected:
  BlockVzConnect(boost::asio::io_service &io_service);
  boost::asio::io_service &io_service_;
 private:
  static const int HEADER_BUFFERR_SIZE = 8;
  char header_buffer_[HEADER_BUFFERR_SIZE];
};

}

#endif //  VZCONN_CONN_VZCONNECT_H_
